<?php

/*
 * This file is part of the phpems/phpems.
 *
 * (c) oiuv <i@oiuv.cn>
 *
 * 项目维护：oiuv(QQ:7300637) | 定制服务：火眼(QQ:278768688)
 *
 * This source file is subject to the MIT license that is bundled.
 */

class wechat
{
    const MSGTYPE_TEXT = 'text';
    const MSGTYPE_IMAGE = 'image';
    const MSGTYPE_LOCATION = 'location';
    const MSGTYPE_LINK = 'link';
    const MSGTYPE_EVENT = 'event';
    const MSGTYPE_MUSIC = 'music';
    const MSGTYPE_NEWS = 'news';
    const MSGTYPE_VOICE = 'voice';
    const MSGTYPE_VIDEO = 'video';
    const API_URL_PREFIX = 'https://api.weixin.qq.com/cgi-bin';
    const AUTH_URL = '/token?grant_type=client_credential&';
    const MENU_CREATE_URL = '/menu/create?';
    const MENU_GET_URL = '/menu/get?';
    const MENU_DELETE_URL = '/menu/delete?';
    const MEDIA_GET_URL = '/media/get?';
    const QRCODE_CREATE_URL = '/qrcode/create?';
    const QR_SCENE = 0;
    const QR_LIMIT_SCENE = 1;
    const QRCODE_IMG_URL = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=';
    const USER_GET_URL = '/user/get?';
    const USER_INFO_URL = '/user/info?';
    const GROUP_GET_URL = '/groups/get?';
    const GROUP_CREATE_URL = '/groups/create?';
    const GROUP_UPDATE_URL = '/groups/update?';
    const GROUP_MEMBER_UPDATE_URL = '/groups/members/update?';

    private $token;
    private $appid;
    private $appsecret;
    private $access_token;
    private $_msg;
    private $_funcflag = false;
    private $_receive;
    public $debug = false;
    public $errCode = 40001;
    public $errMsg = 'no access';
    private $_logcallback;

    public function __construct(&$G)
    {
        $this->G = $G;
    }

    public function showConst($var)
    {
        return self::$var;
    }

    public function init($options)
    {
        $this->token = isset($options['token']) ? $options['token'] : '';
        $this->appid = isset($options['appid']) ? $options['appid'] : WXAPPID;
        $this->appsecret = isset($options['appsecret']) ? $options['appsecret'] : WXAPPSECRET;
        $this->debug = isset($options['debug']) ? $options['debug'] : false;
        $this->_logcallback = isset($options['logcallback']) ? $options['logcallback'] : false;
    }

    /**
     * For weixin server validation.
     */
    private function checkSignature()
    {
        $signature = isset($_GET['signature']) ? $_GET['signature'] : '';
        $timestamp = isset($_GET['timestamp']) ? $_GET['timestamp'] : '';
        $nonce = isset($_GET['nonce']) ? $_GET['nonce'] : '';

        $token = $this->token;
        $tmpArr = [$token, $timestamp, $nonce];
        sort($tmpArr);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        if ($tmpStr == $signature) {
            return true;
        }

        return false;
    }

    /**
     * For weixin server validation.
     *
     * @param bool $return 是否返回
     */
    public function valid($return = false)
    {
        $echoStr = isset($_GET['echostr']) ? $_GET['echostr'] : '';
        if ($return) {
            if ($echoStr) {
                if ($this->checkSignature()) {
                    return $echoStr;
                }

                return false;
            }

            return $this->checkSignature();
        }
        if ($echoStr) {
            if ($this->checkSignature()) {
                die($echoStr);
            }

            die('no access');
        }
        if ($this->checkSignature()) {
            return true;
        }

        die('no access');

        return false;
    }

    /**
     * 设置发送消息.
     *
     * @param array $msg    消息数组
     * @param bool  $append 是否在原消息数组追加
     */
    public function Message($msg = '', $append = false)
    {
        if (is_null($msg)) {
            $this->_msg = [];
        } elseif (is_array($msg)) {
            if ($append) {
                $this->_msg = array_merge($this->_msg, $msg);
            } else {
                $this->_msg = $msg;
            }

            return $this->_msg;
        } else {
            return $this->_msg;
        }
    }

    public function setFuncFlag($flag)
    {
        $this->_funcflag = $flag;

        return $this;
    }

    private function log($log)
    {
        if ($this->debug && function_exists($this->_logcallback)) {
            if (is_array($log)) {
                $log = print_r($log, true);
            }

            return call_user_func($this->_logcallback, $log);
        }
    }

    /**
     * 获取微信服务器发来的信息.
     */
    public function getRev()
    {
        $postStr = file_get_contents('php://input');
        $this->log($postStr);
        if (!empty($postStr)) {
            $this->_receive = (array) simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
        }

        return $this;
    }

    /**
     * 获取微信服务器发来的信息.
     */
    public function getRevData()
    {
        return $this->_receive;
    }

    /**
     * 获取消息发送者.
     */
    public function getRevFrom()
    {
        if ($this->_receive) {
            return $this->_receive['FromUserName'];
        }

        return false;
    }

    /**
     * 获取消息接受者.
     */
    public function getRevTo()
    {
        if ($this->_receive) {
            return $this->_receive['ToUserName'];
        }

        return false;
    }

    /**
     * 获取接收消息的类型.
     */
    public function getRevType()
    {
        if (isset($this->_receive['MsgType'])) {
            return $this->_receive['MsgType'];
        }

        return false;
    }

    /**
     * 获取消息ID.
     */
    public function getRevID()
    {
        if (isset($this->_receive['MsgId'])) {
            return $this->_receive['MsgId'];
        }

        return false;
    }

    /**
     * 获取消息发送时间.
     */
    public function getRevCtime()
    {
        if (isset($this->_receive['CreateTime'])) {
            return $this->_receive['CreateTime'];
        }

        return false;
    }

    /**
     * 获取接收消息内容正文.
     */
    public function getRevContent()
    {
        if (isset($this->_receive['Content'])) {
            return $this->_receive['Content'];
        } elseif (isset($this->_receive['Recognition'])) { //获取语音识别文字内容，需申请开通
            return $this->_receive['Recognition'];
        } else {
            return false;
        }
    }

    /**
     * 获取接收消息图片.
     */
    public function getRevPic()
    {
        if (isset($this->_receive['PicUrl'])) {
            return $this->_receive['PicUrl'];
        }

        return false;
    }

    /**
     * 获取接收消息链接.
     */
    public function getRevLink()
    {
        if (isset($this->_receive['Url'])) {
            return [
                'url'         => $this->_receive['Url'],
                'title'       => $this->_receive['Title'],
                'description' => $this->_receive['Description'],
            ];
        }

        return false;
    }

    /**
     * 获取接收地理位置.
     */
    public function getRevGeo()
    {
        if (isset($this->_receive['Location_X'])) {
            return [
                'x'     => $this->_receive['Location_X'],
                'y'     => $this->_receive['Location_Y'],
                'scale' => $this->_receive['Scale'],
                'label' => $this->_receive['Label'],
            ];
        }

        return false;
    }

    /**
     * 获取接收事件推送
     */
    public function getRevEvent()
    {
        if (isset($this->_receive['Event'])) {
            return [
                'event' => $this->_receive['Event'],
                'key'   => $this->_receive['EventKey'],
            ];
        }

        return false;
    }

    /**
     * 获取接收语言推送
     */
    public function getRevVoice()
    {
        if (isset($this->_receive['MediaId'])) {
            return [
                'mediaid' => $this->_receive['MediaId'],
                'format'  => $this->_receive['Format'],
            ];
        }

        return false;
    }

    /**
     * 获取接收视频推送
     */
    public function getRevVideo()
    {
        if (isset($this->_receive['MediaId'])) {
            return [
                'mediaid'      => $this->_receive['MediaId'],
                'thumbmediaid' => $this->_receive['ThumbMediaId'],
            ];
        }

        return false;
    }

    public static function xmlSafeStr($str)
    {
        return '<![CDATA['.preg_replace('/[\\x00-\\x08\\x0b-\\x0c\\x0e-\\x1f]/', '', $str).']]>';
    }

    /**
     * 数据XML编码
     *
     * @param mixed $data 数据
     *
     * @return string
     */
    public static function data_to_xml($data)
    {
        $xml = '';
        foreach ($data as $key => $val) {
            is_numeric($key) && $key = "item id=\"$key\"";
            $xml .= "<$key>";
            $xml .= (is_array($val) || is_object($val)) ? self::data_to_xml($val) : self::xmlSafeStr($val);
            list($key) = explode(' ', $key);
            $xml .= "</$key>";
        }

        return $xml;
    }

    /**
     * XML编码
     *
     * @param mixed  $data     数据
     * @param string $root     根节点名
     * @param string $item     数字索引的子节点名
     * @param string $attr     根节点属性
     * @param string $id       数字索引子节点key转换的属性名
     * @param string $encoding 数据编码
     *
     * @return string
     */
    public function xml_encode($data, $root = 'xml', $item = 'item', $attr = '', $id = 'id', $encoding = 'utf-8')
    {
        if (is_array($attr)) {
            $_attr = [];
            foreach ($attr as $key => $value) {
                $_attr[] = "{$key}=\"{$value}\"";
            }
            $attr = implode(' ', $_attr);
        }
        $attr = trim($attr);
        $attr = empty($attr) ? '' : " {$attr}";
        $xml = "<{$root}{$attr}>";
        $xml .= self::data_to_xml($data, $item, $id);
        $xml .= "</{$root}>";

        return $xml;
    }

    /**
     * 设置回复消息
     * Examle: $obj->text('hello')->reply();.
     *
     * @param string $text
     */
    public function text($text = '')
    {
        $FuncFlag = $this->_funcflag ? 1 : 0;
        $msg = [
            'ToUserName'   => $this->getRevFrom(),
            'FromUserName' => $this->getRevTo(),
            'MsgType'      => self::MSGTYPE_TEXT,
            'Content'      => $text,
            'CreateTime'   => time(),
            'FuncFlag'     => $FuncFlag,
        ];
        $this->Message($msg);

        return $this;
    }

    /**
     * 设置回复音乐.
     *
     * @param string $title
     * @param string $desc
     * @param string $musicurl
     * @param string $hgmusicurl
     */
    public function music($title, $desc, $musicurl, $hgmusicurl = '')
    {
        $FuncFlag = $this->_funcflag ? 1 : 0;
        $msg = [
            'ToUserName'   => $this->getRevFrom(),
            'FromUserName' => $this->getRevTo(),
            'CreateTime'   => time(),
            'MsgType'      => self::MSGTYPE_MUSIC,
            'Music'        => [
                'Title'       => $title,
                'Description' => $desc,
                'MusicUrl'    => $musicurl,
                'HQMusicUrl'  => $hgmusicurl,
            ],
            'FuncFlag' => $FuncFlag,
        ];
        $this->Message($msg);

        return $this;
    }

    /**
     * 设置回复图文.
     *
     * @param array $newsData
     *                        数组结构:
     *                        array(
     *                        [0]=>array(
     *                        'Title'=>'msg title',
     *                        'Description'=>'summary text',
     *                        'PicUrl'=>'http://www.domain.com/1.jpg',
     *                        'Url'=>'http://www.domain.com/1.html'
     *                        ),
     *                        [1]=>....
     *                        )
     */
    public function news($newsData = [])
    {
        $FuncFlag = $this->_funcflag ? 1 : 0;
        $count = count($newsData);

        $msg = [
            'ToUserName'   => $this->getRevFrom(),
            'FromUserName' => $this->getRevTo(),
            'MsgType'      => self::MSGTYPE_NEWS,
            'CreateTime'   => time(),
            'ArticleCount' => $count,
            'Articles'     => $newsData,
            'FuncFlag'     => $FuncFlag,
        ];
        $this->Message($msg);

        return $this;
    }

    /**
     * 回复微信服务器, 此函数支持链式操作.
     *
     * @example $this->text('msg tips')->reply();
     *
     * @param string $msg    要发送的信息, 默认取$this->_msg
     * @param bool   $return 是否返回信息而不抛出到浏览器 默认:否
     */
    public function reply($msg = [], $return = false)
    {
        if (empty($msg)) {
            $msg = $this->_msg;
        }
        $xmldata = $this->xml_encode($msg);
        $this->log($xmldata);
        if ($return) {
            return $xmldata;
        }

        echo $xmldata;
    }

    /**
     * GET 请求
     *
     * @param string $url
     */
    private function http_get($url)
    {
        $oCurl = curl_init();
        if (false !== stripos($url, 'https://')) {
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
        }
        curl_setopt($oCurl, CURLOPT_URL, $url);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
        $sContent = curl_exec($oCurl);
        $aStatus = curl_getinfo($oCurl);
        curl_close($oCurl);
        if (200 == intval($aStatus['http_code'])) {
            return $sContent;
        }

        return false;
    }

    /**
     * POST 请求
     *
     * @param string $url
     * @param array  $param
     *
     * @return string content
     */
    private function http_post($url, $param)
    {
        $oCurl = curl_init();
        if (false !== stripos($url, 'https://')) {
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
        }
        if (is_string($param)) {
            $strPOST = $param;
        } else {
            $aPOST = [];
            foreach ($param as $key => $val) {
                $aPOST[] = $key.'='.urlencode($val);
            }
            $strPOST = implode('&', $aPOST);
        }
        curl_setopt($oCurl, CURLOPT_URL, $url);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($oCurl, CURLOPT_POST, true);
        curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);
        $sContent = curl_exec($oCurl);
        $aStatus = curl_getinfo($oCurl);
        curl_close($oCurl);
        if (200 == intval($aStatus['http_code'])) {
            return $sContent;
        }

        return false;
    }

    /**
     * 通用auth验证方法，暂时仅用于菜单更新操作.
     *
     * @param string $appid
     * @param string $appsecret
     */
    public function checkAuth($appid = '', $appsecret = '')
    {
        if (!$appid || !$appsecret) {
            $appid = $this->appid;
            $appsecret = $this->appsecret;
        }
        $data = json_decode(file_get_contents(PEPATH.'/data/access_token.json'), true);
        if ($data['expire_time'] < TIME) {
            //TODO: get the cache access_token
            $result = $this->http_get(self::API_URL_PREFIX.self::AUTH_URL.'appid='.$appid.'&secret='.$appsecret);
            if ($result) {
                $json = json_decode($result, true);
                if (!$json || isset($json['errcode'])) {
                    $this->errCode = $json['errcode'];
                    $this->errMsg = $json['errmsg'];

                    return false;
                }
                $this->access_token = $json['access_token'];
                if ($this->access_token) {
                    $data->expire_time = time() + 7000;
                    $data->access_token = $this->access_token;
                    $fp = fopen(PEPATH.'/data/access_token.json', 'w');
                    fwrite($fp, json_encode($data));
                    fclose($fp);
                }
                $expire = $json['expires_in'] ? intval($json['expires_in']) - 100 : 3600;
                //TODO: cache access_token
                return $this->access_token;
            }

            return false;
        }

        $this->access_token = $data['access_token'];

        return $this->access_token;
    }

    /**
     * 删除验证数据.
     *
     * @param string $appid
     */
    public function resetAuth($appid = '')
    {
        $this->access_token = '';
        //TODO: remove cache
        return true;
    }

    /**
     * 微信api不支持中文转义的json结构.
     *
     * @param array $arr
     */
    public static function json_encode($arr)
    {
        $parts = [];
        $is_list = false;
        //Find out if the given array is a numerical array
        $keys = array_keys($arr);
        $max_length = count($arr) - 1;
        if ((0 === $keys[0]) && ($keys[$max_length] === $max_length)) { //See if the first key is 0 and last key is length - 1
            $is_list = true;
            for ($i = 0; $i < count($keys); $i++) { //See if each key correspondes to its position
                if ($i != $keys[$i]) { //A key fails at position check.
                    $is_list = false; //It is an associative array.
                    break;
                }
            }
        }
        foreach ($arr as $key => $value) {
            if (is_array($value)) { //Custom handling for arrays
                if ($is_list) {
                    $parts[] = self::json_encode($value);
                } /* :RECURSION: */
                else {
                    $parts[] = '"'.$key.'":'.self::json_encode($value);
                } /* :RECURSION: */
            } else {
                $str = '';
                if (!$is_list) {
                    $str = '"'.$key.'":';
                }
                //Custom handling for multiple data types
                if (is_numeric($value) && $value < 2000000000) {
                    $str .= $value;
                } //Numbers
                elseif (false === $value) {
                    $str .= 'false';
                } //The booleans
                elseif (true === $value) {
                    $str .= 'true';
                } else {
                    $str .= '"'.addslashes($value).'"';
                } //All other things
                // :TODO: Is there any more datatype we should be in the lookout for? (Object?)
                $parts[] = $str;
            }
        }
        $json = implode(',', $parts);
        if ($is_list) {
            return '['.$json.']';
        } //Return numerical JSON
        return '{'.$json.'}'; //Return associative JSON
    }

    /**
     * 创建菜单.
     *
     * @param array $data 菜单数组数据
     *                    example:
     *                    {
     *                    "button":[
     *                    {
     *                    "type":"click",
     *                    "name":"今日歌曲",
     *                    "key":"MENU_KEY_MUSIC"
     *                    },
     *                    {
     *                    "type":"view",
     *                    "name":"歌手简介",
     *                    "url":"http://www.qq.com/"
     *                    },
     *                    {
     *                    "name":"菜单",
     *                    "sub_button":[
     *                    {
     *                    "type":"click",
     *                    "name":"hello word",
     *                    "key":"MENU_KEY_MENU"
     *                    },
     *                    {
     *                    "type":"click",
     *                    "name":"赞一下我们",
     *                    "key":"MENU_KEY_GOOD"
     *                    }]
     *                    }]
     *                    }
     */
    public function createMenu($data)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_post(self::API_URL_PREFIX.self::MENU_CREATE_URL.'access_token='.$this->access_token, self::json_encode($data));
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return true;
        }

        return false;
    }

    /**
     * 获取菜单.
     *
     * @return array('menu'=>array(....s))
     */
    public function getMenu()
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::MENU_GET_URL.'access_token='.$this->access_token);
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $json;
        }

        return false;
    }

    /**
     * 删除菜单.
     *
     * @return bool
     */
    public function deleteMenu()
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::MENU_DELETE_URL.'access_token='.$this->access_token);
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return true;
        }

        return false;
    }

    /**
     * 根据媒体文件ID获取媒体文件.
     *
     * @param string $media_id 媒体文件id
     *
     * @return raw data
     */
    public function getMedia($media_id)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::MEDIA_GET_URL.'access_token='.$this->access_token.'&media_id='.$media_id);
        if ($result) {
            $json = json_decode($result, true);
            if (isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $result;
        }

        return false;
    }

    /**
     * 创建二维码ticket.
     *
     * @param int $scene_id 自定义追踪id
     * @param int $type     0:临时二维码；1:永久二维码(此时expire参数无效)
     * @param int $expire   临时二维码有效期，最大为1800秒
     *
     * @return array('ticket'=>'qrcode字串','expire_seconds'=>1800)
     */
    public function getQRCode($scene_id, $type = 0, $expire = 1800)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $data = [
            'action_name'    => $type ? 'QR_LIMIT_SCENE' : 'QR_SCENE',
            'expire_seconds' => $expire,
            'action_info'    => ['scene' => ['scene_id' => $scene_id]],
        ];
        $result = $this->http_post(self::API_URL_PREFIX.self::QRCODE_CREATE_URL.'access_token='.$this->access_token, self::json_encode($data));
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $json;
        }

        return false;
    }

    /**
     * 获取二维码图片.
     *
     * @param string $ticket 传入由getQRCode方法生成的ticket参数
     *
     * @return string url 返回http地址
     */
    public function getQRUrl($ticket)
    {
        return self::QRCODE_IMG_URL.$ticket;
    }

    /**
     * 批量获取关注用户列表.
     *
     * @param unknown $next_openid
     */
    public function getUserList($next_openid = '')
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::USER_GET_URL.'access_token='.$this->access_token.'&next_openid='.$next_openid);
        if ($result) {
            $json = json_decode($result, true);
            if (isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $result;
        }

        return false;
    }

    /**
     * 获取关注者详细信息.
     *
     * @param string $openid
     *
     * @return array
     */
    public function getUserInfo($openid)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::USER_INFO_URL.'access_token='.$this->access_token.'&openid='.$openid);
        if ($result) {
            $json = json_decode($result, true);
            if (isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $result;
        }

        return false;
    }

    /**
     * 获取用户分组列表.
     *
     * @return bool|array
     */
    public function getGroup()
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $result = $this->http_get(self::API_URL_PREFIX.self::GROUP_GET_URL.'access_token='.$this->access_token);
        if ($result) {
            $json = json_decode($result, true);
            if (isset($json['errcode'])) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $result;
        }

        return false;
    }

    /**
     * 新增自定分组.
     *
     * @param string $name 分组名称
     *
     * @return bool|array
     */
    public function createGroup($name)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $data = [
            'group' => ['name' => $name],
        ];
        $result = $this->http_post(self::API_URL_PREFIX.self::GROUP_CREATE_URL.'access_token='.$this->access_token, self::json_encode($data));
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $json;
        }

        return false;
    }

    /**
     * 更改分组名称.
     *
     * @param int    $groupid 分组id
     * @param string $name    分组名称
     *
     * @return bool|array
     */
    public function updateGroup($groupid, $name)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $data = [
            'group' => ['id' => $groupid, 'name' => $name],
        ];
        $result = $this->http_post(self::API_URL_PREFIX.self::GROUP_UPDATE_URL.'access_token='.$this->access_token, self::json_encode($data));
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $json;
        }

        return false;
    }

    /**
     * 移动用户分组.
     *
     * @param int    $groupid 分组id
     * @param string $openid  用户openid
     *
     * @return bool|array
     */
    public function updateGroupMembers($groupid, $openid)
    {
        if (!$this->access_token && !$this->checkAuth()) {
            return false;
        }
        $data = [
            'openid'     => $openid,
            'to_groupid' => $groupid,
        ];
        $result = $this->http_post(self::API_URL_PREFIX.self::GROUP_MEMBER_UPDATE_URL.'access_token='.$this->access_token, self::json_encode($data));
        if ($result) {
            $json = json_decode($result, true);
            if (!$json || $json['errcode'] > 0) {
                $this->errCode = $json['errcode'];
                $this->errMsg = $json['errmsg'];

                return false;
            }

            return $json;
        }

        return false;
    }
}
